package com.example.redisdemo.controllerplus;

import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("redis")
public class TestController {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private DistributedLockService distributedLockService;

    @PostMapping("/test2")
    public void test2() {
        String lockKey = "lockKey";
        String requestId = UUID.randomUUID().toString();

        try{
            // 加锁
            while (Boolean.FALSE.equals(this.redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, 3, TimeUnit.SECONDS))) {
                // 重试，循环
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //执行关键代码
            String lock = this.redisTemplate.opsForValue().get("lock");
            if(!StringUtil.isNullOrEmpty(lock)) {
                int i = Integer.parseInt(lock);
                String s = String.valueOf(--i);
                this.redisTemplate.opsForValue().set("lock",s);
                System.out.println("lock:"+s);
            }
        }finally {
            // 先判断再解锁，使用LUA脚本实现分布式锁，来保证原子性
//            String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            String script = "if redis.call('get',KEYS[1]) == ARGV[1] " +
                    "then " +
                    "   return redis.call('del',KEYS[1]) " +
                    "else " +
                    "   return 0 " +
                    "end";
            this.redisTemplate.execute(new DefaultRedisScript<>(script,Long.class), Collections.singletonList(lockKey),requestId);

        }
    }

    @PostMapping("/test1")
    public void test() {
        String lockKey = "lockKey";
        String requestId = UUID.randomUUID().toString();
        long expireTime = 50000; // 锁的过期时间，单位为毫秒

        try{
            while (!distributedLockService.tryLock(lockKey,requestId,expireTime)) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //执行关键代码
            String lock = this.redisTemplate.opsForValue().get("lock");
            if(!StringUtil.isNullOrEmpty(lock)) {
                int i = Integer.parseInt(lock);
                String s = String.valueOf(--i);
                this.redisTemplate.opsForValue().set("lock",s);
                System.out.println("lock:"+s);
            }
        }finally {
            // 无论如何最后都要释放锁
            distributedLockService.releaseLock(lockKey, requestId);
        }
    }
}
